﻿using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;

using Swashbuckle.AspNetCore.SwaggerGen;

namespace Tszy.Unlimited.AspNetCore.Extensions;

/// <summary>
/// 
/// </summary>
internal static class SwaggerExtensions
{
    /// <summary>
    /// 注册 Swagger。
    /// </summary>
    /// <param name="services"></param>
    /// <param name="title"></param>
    /// <param name="description"></param>
    /// <param name="version"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    public static IServiceCollection RegisterSwagger(this IServiceCollection services, string title, string description = "", string version = "", Action<SwaggerGenOptions>? action = null)
    {
        services.AddSwaggerGen(options =>
        {
            options.SwaggerDoc("v1", new OpenApiInfo()
            {
                Version = version ?? string.Empty,
                Title = title ?? string.Empty,
                Description = description ?? string.Empty,
            });

            // 这里需要另行设置 SchemaIds 为命名空间 + 类名全名。
            // 由于这里默认是使用类名做为 Id。所以，当两个类名一样，命名空间不一样的类就会出错。
            options.CustomSchemaIds(CustomSchemaIdSelector);

            static string CustomSchemaIdSelector(Type modelType)
            {
                if (!modelType.IsConstructedGenericType)
                    return modelType?.FullName?.Replace("[]", "Array").Replace("+", ".") ?? string.Empty;

                var prefix = modelType.GetGenericArguments()
                    .Select(genericArg => CustomSchemaIdSelector(genericArg))
                    .Aggregate((previous, current) => previous + current);

                return prefix + modelType?.FullName?.Split('`').FirstOrDefault()?.Replace("+", ".") ?? string.Empty;
            }

            #region swagger鉴权

            options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "Value: Bearer {token}",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey,
                Scheme = "Bearer"
            });

            options.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                        },Scheme = "oauth2",Name = "Bearer",In = ParameterLocation.Header,
                    },new List<string>()
                    }
                });

            action?.Invoke(options);

            #endregion
        });

        return services;
    }

    /// <summary>
    /// 启用 Swagger。
    /// </summary>
    /// <param name="app"></param>
    /// <param name="isDevelopment"></param>
    public static void UseApiSwagger(this WebApplication app, bool isDevelopment = true)
    {
        if (isDevelopment)
        {
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }
        }
        else
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }
    }
}